{-# LANGUAGE ScopedTypeVariables        #-}
{-# OPTIONS -Wall #-}

--------------------------------------------------------------------------------
-- |
-- Module      :  Orca.Csound.SignalModifiers
-- Copyright   :  (c) Stephen Tetley 2013
-- License     :  BSD3
--
-- Maintainer  :  stephen.tetley@gmail.com
-- Stability   :  unstable
-- Portability :  GHC
--
-- Signal modifying opcodes.
-- 
--------------------------------------------------------------------------------

module Orca.Csound.SignalModifiers
  (


  -- * Standard filters
    cs_portk
  , cs_port
  , cs_tonek
  , cs_tone
  , cs_atonek
  , cs_atone
  , cs_resonk
  , cs_reson
  , cs_aresonk
  , cs_areson
  , cs_tonex
  , cs_atonex
  , cs_resonx
  , cs_resonr
  , cs_resonz
  , cs_resony
  , cs_lowres
  , cs_lowresx
  , cs_vlowres
  , cs_lowpass2
  , cs_hilbert
  , cs_butterhp
  , cs_butterhp_
  , cs_butterlp
  , cs_butterlp_
  , cs_butterbp
  , cs_butterbp_
  , cs_butterbr
  , cs_butterbr_


  -- * Specialized filters
  , cs_nlfilt
  , cs_pareq
  , cs_dcblock
  , cs_dcblock_

  -- * Envelope modifiers
  , cs_linen
  , cs_linenr
  , cs_envlpx
  , cs_envlpxr

  -- * Amplitude modifiers
  , cs_rms
  , cs_rms_
  , cs_gain
  , cs_balance
  , cs_dam

  -- * signal limiters
  , cs_wrap
  , cs_mirror
  , cs_limit

  -- * Delay
  , cs_delayr
  , cs_delayw
  , cs_delay
  , cs_delay1
  , cs_deltap
  , cs_deltapi
  , cs_deltapn
  , cs_deltap3

  , cs_multitap
  , cs_vdelay
  , cs_vdelay3

  -- * Reverbaration
  , cs_reverb
  , cs_reverb2
  , cs_nreverb
  , cs_comb
  , cs_alpass
  , cs_babo
  , cs_nestedap
  , cs_reverbsc

  -- * Panning and spatialization
  , cs_pan
  , cs_pan2
  , cs_locsig
  , cs_locsig2


  ) where

import Orca.Csound.Monad
import Orca.Csound.Syntax


--------------------------------------------------------------------------------
-- Standard filters


cs_portk :: KSig -> KSig -> Orca KSig
cs_portk ksig khtim = 
    genOpcode1 K_RATE "portk" [ getPExpr ksig, getPExpr khtim ]



cs_port :: KSig -> ISig -> Orca KSig
cs_port ksig ihtim = 
    genOpcode1 K_RATE "port" [ getPExpr ksig, getPExpr ihtim ]


cs_tonek :: KSig -> KSig -> Orca KSig
cs_tonek ksig khp = 
    genOpcode1 K_RATE "tonek" [ getPExpr ksig, getPExpr khp ]


cs_tone :: ASig -> KSig -> Orca ASig
cs_tone asig khp = 
    genOpcode1 A_RATE "tone" [ getPExpr asig, getPExpr khp ]

cs_atonek :: KSig -> KSig -> Orca KSig
cs_atonek ksig khp = 
    genOpcode1 K_RATE "atonek" [ getPExpr ksig, getPExpr khp ]

cs_atone :: ASig -> KSig -> Orca ASig
cs_atone asig khp = 
    genOpcode1 A_RATE "atone" [ getPExpr asig, getPExpr khp ]


cs_resonk :: KSig -> KSig -> KSig -> Orca KSig
cs_resonk ksig kcf kbw = 
    genOpcode1 K_RATE "resonk" [ getPExpr ksig, getPExpr kcf
                               , getPExpr kbw ]

cs_reson :: ASig -> KSig -> KSig -> Orca ASig
cs_reson asig kcf kbw = 
    genOpcode1 A_RATE "reson" [ getPExpr asig, getPExpr kcf
                              , getPExpr kbw ]

cs_aresonk :: KSig -> KSig -> KSig -> Orca KSig
cs_aresonk ksig kcf kbw = 
    genOpcode1 K_RATE "aresonk" [ getPExpr ksig, getPExpr kcf
                                , getPExpr kbw ]

cs_areson :: ASig -> KSig -> KSig -> Orca ASig
cs_areson asig kcf kbw = 
    genOpcode1 A_RATE "areson" [ getPExpr asig, getPExpr kcf
                               , getPExpr kbw ]


cs_tonex :: ASig -> KSig -> Orca ASig
cs_tonex asig khp = 
    genOpcode1 A_RATE "tonex" [ getPExpr asig, getPExpr khp ]

cs_atonex :: ASig -> KSig -> Orca ASig
cs_atonex asig khp = 
    genOpcode1 A_RATE "atonex" [ getPExpr asig, getPExpr khp ]


cs_resonx :: ASig -> KSig -> KSig -> Orca ASig
cs_resonx asig kcf kbw = 
    genOpcode1 A_RATE "resonx" [ getPExpr asig, getPExpr kcf
                               , getPExpr kbw ]

cs_resonr :: ASig -> KSig -> KSig -> Orca ASig
cs_resonr asig kcf kbw = 
    genOpcode1 A_RATE "resonr" [ getPExpr asig, getPExpr kcf
                               , getPExpr kbw ]

cs_resonz :: ASig -> KSig -> KSig -> Orca ASig
cs_resonz asig kcf kbw = 
    genOpcode1 A_RATE "resonz" [ getPExpr asig, getPExpr kcf
                               , getPExpr kbw ]

cs_resony :: ASig -> KSig -> KSig -> IInt -> KSig -> Orca ASig
cs_resony asig kbf kbw inum ksep = 
    genOpcode1 A_RATE "resony" [ getPExpr asig, getPExpr kbf
                               , getPExpr kbw,  getPExpr inum
                               , getPExpr ksep ]

cs_lowres :: ASig -> KSig -> KSig -> Orca ASig
cs_lowres asig kcutoff kresonance = 
    genOpcode1 A_RATE "lowres" [ getPExpr asig, getPExpr kcutoff
                               , getPExpr kresonance ]

cs_lowresx :: ASig -> KSig -> KSig -> Orca ASig
cs_lowresx asig kcutoff kresonance = 
    genOpcode1 A_RATE "lowresx" [ getPExpr asig, getPExpr kcutoff
                                , getPExpr kresonance ]


-- | Note @iord@ could be a var representing a pfield rather than 
-- always an @Int@...
--
cs_vlowres :: ASig -> KSig -> KSig -> IInt -> KSig -> Orca ASig
cs_vlowres asig kfco kres iord ksep = 
    genOpcode1 A_RATE "vlowres" [ getPExpr asig, getPExpr kfco
                                , getPExpr kres, getPExpr iord
                                , getPExpr ksep ]


cs_lowpass2 :: ASig -> KSig -> KSig -> Orca ASig
cs_lowpass2 asig kef kq = 
    genOpcode1 A_RATE "lowpass2" [ getPExpr asig, getPExpr kef
                                 , getPExpr kq ]


cs_hilbert :: ASig -> Orca (ASig,ASig)
cs_hilbert asig = 
    genOpcode2 A_RATE "hilbert" [ getPExpr asig ]

cs_butterhp :: ASig -> KSig -> Orca ASig
cs_butterhp asig kfreq = 
    genOpcode1 A_RATE "butterhp" [ getPExpr asig, getPExpr kfreq ]

-- Int used a boolean...
--
cs_butterhp_ :: ASig -> KSig -> IInt -> Orca ASig
cs_butterhp_ asig kfreq isep = 
    genOpcode1 A_RATE "butterhp" [ getPExpr asig, getPExpr kfreq
                                 , getPExpr isep ]


cs_butterlp :: ASig -> KSig -> Orca ASig
cs_butterlp asig kfreq = 
    genOpcode1 A_RATE "butterlp" [ getPExpr asig, getPExpr kfreq ]

cs_butterlp_ :: ASig -> KSig -> IInt -> Orca ASig
cs_butterlp_ asig kfreq iskip = 
    genOpcode1 A_RATE "butterlp" [ getPExpr asig, getPExpr kfreq
                                 , getPExpr iskip ]

cs_butterbp :: ASig -> KSig -> KSig -> Orca ASig
cs_butterbp asig kfreq kband = 
    genOpcode1 A_RATE "butterbp" [ getPExpr asig, getPExpr kfreq
                                 , getPExpr kband ]


cs_butterbp_ :: ASig -> KSig -> KSig -> IInt -> Orca ASig
cs_butterbp_ asig kfreq kband iskip = 
    genOpcode1 A_RATE "butterbp" [ getPExpr asig,  getPExpr kfreq
                                 , getPExpr kband, getPExpr iskip ]

cs_butterbr :: ASig -> KSig -> KSig -> Orca ASig
cs_butterbr asig kfreq kband = 
    genOpcode1 A_RATE "butterbr" [ getPExpr asig, getPExpr kfreq
                                 , getPExpr kband ]

cs_butterbr_ :: ASig -> KSig -> KSig -> IInt -> Orca ASig
cs_butterbr_ asig kfreq kband iskip = 
    genOpcode1 A_RATE "butterbr" [ getPExpr asig,  getPExpr kfreq
                                 , getPExpr kband, getPExpr iskip ]


--------------------------------------------------------------------------------
-- Specialized filters


cs_nlfilt :: ASig -> KSig -> KSig 
          -> KSig -> KSig -> KSig 
          -> Orca ASig
cs_nlfilt ain ka kb kd kL kC = 
    genOpcode1 A_RATE "nlfilt" [ getPExpr ain, getPExpr ka
                               , getPExpr kb,  getPExpr kd
                               , getPExpr kL,  getPExpr kC ]


cs_pareq :: ASig -> KSig -> KSig 
         -> KSig -> IInt -> IInt 
         -> Orca ASig
cs_pareq asig kc kv kq imode iskip = 
    genOpcode1 A_RATE "pareq" [ getPExpr asig,  getPExpr kc
                              , getPExpr kv,    getPExpr kq
                              , getPExpr imode, getPExpr iskip ]

cs_dcblock :: ASig -> Orca ASig
cs_dcblock asig = 
    genOpcode1 A_RATE "dcblock" [ getPExpr asig ]

cs_dcblock_ :: ASig -> IFloat -> Orca ASig
cs_dcblock_ asig ig = 
    genOpcode1 A_RATE "dcblock" [ getPExpr asig, getPExpr ig ]

--------------------------------------------------------------------------------
-- Envelope modifiers



cs_linen :: forall r1. IKA_Signal r1
         => Sig r1 -> IFloat -> IFloat -> IFloat -> Orca (Sig r1)
cs_linen xamp irise idur idec = 
    genOpcode1 rid "linen" [ getPExpr xamp, getPExpr irise
                           , getPExpr idur, getPExpr idec ]
  where
    rid = genRate (undefined :: r1)

cs_linenr :: forall r1. IKA_Signal r1
          => Sig r1 -> IFloat -> IFloat -> IFloat -> Orca (Sig r1)
cs_linenr xamp irise idec iatdec = 
    genOpcode1 rid "linenr" [ getPExpr xamp, getPExpr irise
                            , getPExpr idec, getPExpr iatdec ]
  where
    rid = genRate (undefined :: r1)



cs_envlpx :: forall r1. IKA_Signal r1
          => Sig r1 -> IFloat -> IFloat -> IFloat 
          -> TableIx -> IFloat -> IFloat 
          -> Orca (Sig r1)
cs_envlpx xamp irise idur idec ifn iatss iatdec = 
    genOpcode1 rid "envlpx" [ getPExpr xamp, getPExpr irise
                            , getPExpr idur, getPExpr idec
                            , getPExpr ifn,  getPExpr iatss
                            , getPExpr iatdec ]
  where
    rid = genRate (undefined :: r1)


cs_envlpxr :: forall r1 . IKA_Signal r1
           => Sig r1 -> IFloat -> IFloat 
           -> IFloat  -> IInt -> IFloat -> IFloat 
           -> Orca (Sig r1)
cs_envlpxr xamp irise idur idec ifn iatss iatdec = 
    genOpcode1 rid "envlpxr" [ getPExpr xamp, getPExpr irise
                             , getPExpr idur, getPExpr idec
                             , getPExpr ifn,  getPExpr iatss
                             , getPExpr iatdec ]
  where
    rid = genRate (undefined :: r1)

--------------------------------------------------------------------------------
-- Amplitude modifiers


cs_rms :: ASig -> Orca KSig
cs_rms asig =
    genOpcode1 A_RATE "rms" [ getPExpr asig ]

cs_rms_ :: ASig -> IFloat -> IFloat -> Orca KSig
cs_rms_ asig ihp iskip = 
    genOpcode1 A_RATE "rms" [ getPExpr asig, getPExpr ihp
                            , getPExpr iskip ]

cs_gain :: ASig -> KSig -> Orca ASig
cs_gain asig krms = 
    genOpcode1 A_RATE "gain" [ getPExpr asig, getPExpr krms ]

cs_balance :: ASig -> ASig -> Orca ASig
cs_balance asig acomp = 
    genOpcode1 A_RATE "balance" [ getPExpr asig, getPExpr acomp ]

cs_dam :: ASig -> KSig 
       -> IFloat -> IFloat -> IFloat -> IFloat 
       -> Orca ASig
cs_dam ain kthreshold icomp1 icomp2 rtime ftime = 
    genOpcode1 A_RATE "dam" [ getPExpr ain,    getPExpr kthreshold
                            , getPExpr icomp1, getPExpr icomp2
                            , getPExpr rtime,  getPExpr ftime ]

--------------------------------------------------------------------------------
-- Signal limiters


cs_wrap :: forall r1. IKA_Signal r1 
        => Sig r1 -> Sig r1 -> Sig r1 -> Orca (Sig r1)
cs_wrap xsig xlow xhigh = 
    genOpcode1 rid "wrap" [ getPExpr xsig, getPExpr xlow
                          , getPExpr xhigh ]
  where
    rid = genRate (undefined :: r1)



cs_mirror :: forall r1. IKA_Signal r1 
          => Sig r1 -> Sig r1 -> Sig r1 -> Orca (Sig r1)
cs_mirror xsig xlow xhigh = 
    genOpcode1 rid "mirror" [ getPExpr xsig, getPExpr xlow
                            , getPExpr xhigh ]
  where
    rid = genRate (undefined :: r1)

cs_limit :: forall r1. IKA_Signal r1 
         => Sig r1 -> Sig r1 -> Sig r1 -> Orca (Sig r1)
cs_limit xsig xlow xhigh = 
    genOpcode1 rid "limit" [ getPExpr xsig, getPExpr xlow
                           , getPExpr xhigh ]
  where
    rid = genRate (undefined :: r1)


--------------------------------------------------------------------------------
-- Delay


cs_delayr :: IFloat -> Orca ASig
cs_delayr idlt = 
    genOpcode1 A_RATE "delayr" [ getPExpr idlt ]

-- | No answer ... sure?
cs_delayw :: ASig -> Orca ()
cs_delayw asigar = 
    genOpcode0 "delayw" [ getPExpr asigar ]

cs_delay :: ASig -> IFloat -> Orca ASig
cs_delay asig idlt = 
    genOpcode1 A_RATE "delay" [ getPExpr asig, getPExpr idlt ]

cs_delay1 :: ASig -> Orca ASig
cs_delay1 asig = 
    genOpcode1 A_RATE "delay1" [ getPExpr asig ]

cs_deltap :: KSig -> Orca ASig
cs_deltap kdlt = 
    genOpcode1 A_RATE "deltap" [ getPExpr kdlt ]

-- | xdlt is seconds, but it can be a signal...
--
cs_deltapi :: IKA_Signal r1 => Sig r1 -> Orca ASig
cs_deltapi xdlt = 
    genOpcode1 A_RATE "deltapi" [ getPExpr xdlt ]

-- | xnumsamps is presumably an integer...
--
cs_deltapn :: IKA_Signal r1 => Sig r1 -> Orca ASig
cs_deltapn xnumsamps = 
    genOpcode1 A_RATE "deltapn" [ getPExpr xnumsamps ]


-- | xdlt is seconds...
--
cs_deltap3 :: IKA_Signal r1 => Sig r1 -> Orca ASig
cs_deltap3 xdlt = 
    genOpcode1 A_RATE "deltap3" [ getPExpr xdlt ]

-- | Genuine list - not an envelope...
--
cs_multitap :: ASig -> [(IFloat, IFloat)] -> Orca ASig
cs_multitap asig xs = genOpcode1 A_RATE "multitap"  (getPExpr asig : rest) 
  where
    rest = concatMap (\(a,b) -> [getPExpr a, getPExpr b]) xs
     


cs_vdelay :: ASig -> ASig -> IFloat -> Orca ASig
cs_vdelay asig adel imaxdel = 
    genOpcode1 A_RATE "vdelay" [ getPExpr asig,   getPExpr adel
                               , getPExpr imaxdel ]

cs_vdelay3 :: ASig -> ASig -> IFloat -> Orca ASig
cs_vdelay3 asig adel imaxdel = 
    genOpcode1 A_RATE "vdelay3" [ getPExpr asig,   getPExpr adel
                                , getPExpr imaxdel ]

--------------------------------------------------------------------------------
-- Reverberation


cs_reverb :: ASig -> KSig -> Orca ASig
cs_reverb asig kvrt = 
    genOpcode1 A_RATE "reverb" [ getPExpr asig, getPExpr kvrt ]

cs_reverb2 :: ASig -> KSig -> KSig -> Orca ASig
cs_reverb2 asig ktime khdif = 
    genOpcode1 A_RATE "reverb2" [ getPExpr asig, getPExpr ktime
                                , getPExpr khdif ]

cs_nreverb :: ASig -> KSig -> KSig -> Orca ASig
cs_nreverb asig ktime khdif = 
    genOpcode1 A_RATE "nreverb" [ getPExpr asig, getPExpr ktime
                                , getPExpr khdif ]

cs_comb :: ASig -> KSig -> IFloat -> Orca ASig
cs_comb asig krvt ilpt = 
    genOpcode1 A_RATE "comb" [ getPExpr asig, getPExpr krvt
                             , getPExpr ilpt ]

cs_alpass :: ASig -> KSig -> IFloat -> Orca ASig
cs_alpass asig krvt ilpt = 
    genOpcode1 A_RATE "alpass" [ getPExpr asig, getPExpr krvt
                               , getPExpr ilpt ]

cs_babo :: ASig -> KSig -> KSig -> KSig -> IFloat -> IFloat -> IFloat 
     -> Orca (ASig,ASig)
cs_babo asig ksrcx ksrcy ksrcz irx iry irz =
    genOpcode2 A_RATE "babo" [ getPExpr asig,  getPExpr ksrcx
                             , getPExpr ksrcy, getPExpr ksrcz
                             , getPExpr irx,   getPExpr iry
                             , getPExpr irz ]

cs_nestedap :: ASig -> IFloat -> IFloat -> IFloat -> IFloat -> Orca ASig
cs_nestedap asig imode imaxdel idel1 igain1 = 
    genOpcode1 A_RATE "nestedap" [ getPExpr asig,    getPExpr imode
                                 , getPExpr imaxdel, getPExpr idel1
                                 , getPExpr igain1 ]



cs_reverbsc :: ASig -> ASig -> KSig -> KSig -> Orca (ASig,ASig)
cs_reverbsc ainL ainR kfblvl kfco = 
    genOpcode2 A_RATE "reverbsc" [ getPExpr ainL,   getPExpr ainR
                                 , getPExpr kfblvl, getPExpr kfco ]

--------------------------------------------------------------------------------
-- Panning and spatialization

-- Note - name /priority/ is given to the 4 channel versions.


-- | 4 channel pan.
--
-- 1 Table fn.
--
cs_pan :: ASig -> KSig -> KSig -> TableIx -> Orca (ASig,ASig,ASig,ASig)
cs_pan asig kx ky ifn = 
    genOpcode4 A_RATE "pan" [ getPExpr asig, getPExpr kx
                            , getPExpr ky,   getPExpr ifn ]


cs_pan2 :: IKA_Signal a => ASig -> Sig a -> Orca (ASig,ASig)
cs_pan2 asig xp = 
    genOpcode2 A_RATE "pan2" [ getPExpr asig, getPExpr xp ]


-- | 4 channel version of locsig.
--
cs_locsig :: ASig -> KSig -> KSig -> KSig -> Orca (ASig,ASig,ASig,ASig)
cs_locsig asig kdegree kdistance kreverbsend = 
    genOpcode4 A_RATE "locsig" [ getPExpr asig,      getPExpr kdegree
                               , getPExpr kdistance, getPExpr kreverbsend ]


-- | This is the 2 channel version of 'locsig'
--
cs_locsig2 :: ASig -> KSig -> KSig -> KSig -> Orca (ASig,ASig)
cs_locsig2 asig kdegree kdistance kreverbsend = 
    genOpcode2 A_RATE "locsig" [ getPExpr asig,      getPExpr kdegree
                               , getPExpr kdistance, getPExpr kreverbsend ]


